/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年5月30日
 */
package com.massyframework.beanskin.runtime.framework;

import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.ModuleInstalledEvent;
import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.ModuleJarsLocator;
import com.massyframework.beanskin.ModuleRuntimeException;
import com.massyframework.beanskin.StartStopAbility;
import com.massyframework.beanskin.assembly.Assembly;
import com.massyframework.beanskin.framework.FrameworkDestroyingEvent;
import com.massyframework.beanskin.framework.FrameworkEvent;
import com.massyframework.beanskin.framework.FrameworkInitializedEvent;
import com.massyframework.beanskin.framework.FrameworkInitializingEvent;
import com.massyframework.beanskin.library.LibraryBuilder;
import com.massyframework.beanskin.plugin.PluginBuilder;
import com.massyframework.beanskin.runtime.ModuleEventPublisher;
import com.massyframework.beanskin.runtime.ModuleRegistry;
import com.massyframework.beanskin.runtime.framework.installing.assembly.AssemblyInstaller;
import com.massyframework.beanskin.runtime.framework.installing.fragment.FragmentMonitor;
import com.massyframework.beanskin.runtime.framework.installing.library.LibraryInstaller;
import com.massyframework.beanskin.runtime.framework.installing.plugin.PluginInstaller;
import com.massyframework.beanskin.util.exceptioncollect.ExceptionCollectUtils;
import com.massyframework.beanskin.util.localstore.LocalStore;

/**
 * 执行初始化的运行框架基类
 * @author huangkh
 *
 */
abstract class InitializingFramework extends AbstractFramework {

	private Logger logger = LoggerFactory.getLogger(InitializingFramework.class);
	private boolean inited = false;
	private FragmentMonitor fragmentMonitor;
		
	/**
	 * @param builder
	 */
	public InitializingFramework(Builder builder) {
		super(builder);
	}

	@Override
	public synchronized void init(){
		if (this.inited) return ;
		this.inited = true;
		
		FrameworkEvent event = new FrameworkInitializingEvent(this);
		this.applyEvent(event);
		
		Assembly kernel = this.getKernelAssembly();
		try {
			//参数
			LocalStore localStore = kernel.getAssemblyContext()
					.getBean(LocalStore.class.getName(), LocalStore.class);
			ModuleJarsLocator moduleJarsLocator = kernel.getAssemblyContext()
					.getBean(ModuleJarsLocator.class.getName(), ModuleJarsLocator.class);
			
			this.fragmentMonitor = 
					FragmentMonitor.newBuilder()
						.framework(this)
						.kernel(kernel)
						.moduleJarsLocator(moduleJarsLocator)
						.moduleRepository(this.getModuleRepository())
						.serviceRepositoryFactory(this.getServiceRepositoryFactory())
						.localStore(localStore)
						.build();
		
			//扫描并注册类空
			LibraryInstaller libraryInstaller = new LibraryInstaller();
			List<LibraryBuilder> builders =libraryInstaller.loadingLibraries(kernel, localStore);
			libraryInstaller.installLibrarys(builders, moduleJarsLocator, this.getModuleRepository(), kernel,
					this.getServiceRepositoryFactory());
			
			//扫描并注册插件
			ExecutorService taskExecutor = new ExceptionCollectExecutorService(Executors.newFixedThreadPool(4));			
			PluginInstaller pluginInstaller = new PluginInstaller();
			List<PluginBuilder> pluginBuilders = pluginInstaller.loadingPlugins(kernel, localStore);
			pluginInstaller.installPlugins(pluginBuilders, moduleJarsLocator, this.getModuleRepository(),
					this.getServiceRepositoryFactory(), this, kernel, taskExecutor);
			taskExecutor.shutdown();
			try {
			  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
			} catch (InterruptedException e) {

			}
			
			//扫描并注册装配件
			taskExecutor = new ExceptionCollectExecutorService(Executors.newFixedThreadPool(4));		
			AssemblyInstaller assemblyInstaller = new AssemblyInstaller();
			assemblyInstaller.installAssemblies(kernel, localStore, this.getModuleRepository(),
					this.getServiceRepositoryFactory(), taskExecutor);
			taskExecutor.shutdown();
			try {
			  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
			} catch (InterruptedException e) {

			}
		}catch(Exception e) {
			if (logger.isErrorEnabled()) {
				logger.error(e.getMessage(), e);
			}
			ExceptionCollectUtils.addException(
					new ModuleRuntimeException(kernel, e));
		}
			
		
		event = new FrameworkInitializedEvent(this);
		this.applyEvent(event);
		
		this.publishModuleInstalledEvent();
		
		
		if (kernel.getAssemblyContext().containsBean(StartStopAbility.class.getName())) {
			StartStopAbility hook = 
					kernel.getAssemblyContext().getBean(StartStopAbility.class.getName(), StartStopAbility.class);
			try {
				hook.start();
			}catch(Exception e) {
				if (logger.isErrorEnabled()) {
					logger.error(e.getMessage(), e);
				}
				ExceptionCollectUtils.addException(
						new ModuleRuntimeException(kernel, e));
			}
		}		
	}
	
	
	@Override
	public final synchronized void destory() {
		//销毁事件
		FrameworkDestroyingEvent event = new FrameworkDestroyingEvent(this);
		this.applyEvent(event);
		
		ModuleRegistry registry = (ModuleRegistry)this.getModuleRepository();
		registry.unregisterPlugins();
		
		this.fragmentMonitor = null;
				
		Assembly kernel = this.getKernelAssembly();
		if (kernel.getAssemblyContext().containsBean(StartStopAbility.class.getName())) {
			StartStopAbility hook = 
					kernel.getAssemblyContext().getBean(StartStopAbility.class.getName(), StartStopAbility.class);
			try {
				hook.stop();
			}catch(Exception e) {
				if (logger.isErrorEnabled()) {
					logger.error(e.getMessage(), e);
				}
				ExceptionCollectUtils.addException(
						new ModuleRuntimeException(kernel, e));
			}
		}
		
		if (kernel instanceof StartStopAbility) {
			try {
				((StartStopAbility)kernel).stop();
			} catch (Exception e) {
				if (logger.isErrorEnabled()) {
					logger.error(e.getMessage(), e);
				}
			}
		}
		
		super.destory();
	}
	
	/**
	 * 判断是否已初始化
	 * @return {@link boolean},返回{@code true}表示是，否则返回{@code false}
	 */
	protected synchronized boolean inited() {
		return this.inited;
	}
	
	/**
	 * 发布模块安装事件
	 */
	protected void publishModuleInstalledEvent() {
		Assembly kernel = this.getKernelAssembly();
		Set<ModuleIdentifier> deployModules = this.getDeployModules();
		if (deployModules.isEmpty()) return;
		
		ModuleEventPublisher eventPublisher = (ModuleEventPublisher)this.getModuleRepository();
		for (ModuleIdentifier identifier: deployModules) {
			if (kernel.isModuleIdentifier(identifier)) {
				continue;
			}
			
			Module<?> module = this.getModuleRepository().findModuleByIdentifier(identifier);
			if (module != null) {
				ModuleInstalledEvent event = new ModuleInstalledEvent(module);
				eventPublisher.applyEvent(event);
			}
		}
		this.clearDeployModules();
	}
	
	/**
	 * 片段监视器
	 * @return {@link FragmentMonitor}
	 */
	protected FragmentMonitor getFragmentMonitor() {
		return this.fragmentMonitor;
	}
}
